﻿using System;
using System.Collections;
using System.Xml;
using NeuralNetwork.Generic;
using NeuralNetwork.OutputTypes;

namespace NeuralNetwork.Neurons
{
    class OutputNeuron : Neuron
    {
        protected static Factory<Output> outputFactory = new Factory<Output>();
        protected Output output = null;

        public OutputNeuron(Network network) : base(network)
        {
            output = null;
        }

        public Output Output
        {
            get { return output; }
            set { output = value; }
        }

        public bool Check()
        {
            return (value >= 0);
        }

        public override bool Update()
        {
            // Determine the output of the neuron
            value = network.activation.Call(potential) - network.ActivationThreshold;            
            return Check();
        }

        public override string ToString()
        {             
            if (output != null)
                return output.ToString() + "( " + ID.ToString() + " )";
            else
                return "null";
        }

        public override XmlNode Save(XmlDocument doc, XmlNode parent)
        {
            XmlNode node = base.Save(doc, parent);
            
            XmlNode outputNode = network.AddChildToNode(doc, node, "output", null);
            if (output != null)
            {
                Type outputType = output.GetType();
                XmlAttribute attr = doc.CreateAttribute("typename");
                attr.Value = outputType.Name;
                outputNode.Attributes.Append(attr);
                
                if (outputType.IsGenericType)
                {
                    Type[] typeArguments = outputType.GetGenericArguments();
                    attr = doc.CreateAttribute("generictype");
                    attr.Value = typeArguments[0].FullName; // First T only
                    outputNode.Attributes.Append(attr);
                }
                
                output.Save(doc, outputNode);
            }
            return node;
        }

        public override void Load(XmlNode neuronNode)
        {            
            // Get Output Value            
            foreach (XmlNode n in neuronNode.ChildNodes)
            {
                switch (n.Name.ToUpper())
                {
                    case "OUTPUT":
                        string t = "";
                        string genericType = "";
                        foreach (XmlAttribute attr in n.Attributes)
                        {
                            if (attr.Name.ToUpper() == "TYPENAME") t = attr.Value.Trim();
                            if (attr.Name.ToUpper() == "GENERICTYPE") genericType = attr.Value.Trim();
                        }

                        if (t != "") 
                        {    
                            if (genericType != "")
                                output = outputFactory.Make(t, genericType, n);
                            else
                                output = outputFactory.Make(t, n);
                        }
                        break;

                    default:
                        //ignore
                        break;
                }
            }

            base.Load(neuronNode);
        }
    }
}
